package ru.niir.goodfil.ui;

import ru.niir.goodfil.utils.PricelistItem;
import ru.niir.goodfil.utils.filters.GoodsFilter;
import ru.niir.goodfil.ui.utils.PageIndex;
import ru.niir.goodfil.ui.utils.FilePublisher;
import ru.niir.goodfil.db.ClientGroup;
import ru.niir.goodfil.db.Good;
import ru.niir.goodfil.db.GoodType;
import ru.niir.goodfil.db.Brand;
import ru.niir.goodfil.exceptions.ValidationException;

import java.util.*;
import java.io.*;

import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
//import org.apache.poi.hssf.record.formula.eval.ConcatEval;

import javax.servlet.http.HttpServletRequest;

import ru.niir.goodfil.utils.validation.ValidationError;
import ru.niir.goodfil.utils.validation.ValidationResult;

/**
 * Бин для обработки пользовательских запросов при работе со страницей PricelistPlain.jsp
 */
public class PricelistsPlainRequestBean extends PageBean
{
    private static Logger logger = Logger.getLogger(PricelistsPlainRequestBean.class);

    //
    //  НАСТРОЙКИ ---------------------------------------------------------
    //

    /**
     * Название настройки, задающей размер страницы
     */
    private static final String PRICELIST_PAGE_SIZE_KEY = ".pricelist.page.size";

    /**
     * Название настройки, задающей отступ от текущей страницы влево для пэйджинатора
     */
    private static final String PRICELIST_LEFT_PAGE_OFFSET_SIZE = ".pricelist.page.left.offset";

    /**
     * Название настройки, задающей отступ от текущей страницы вправо для пэйджинатора
     */
    private static final String PRICELIST_RIGHT_PAGE_OFFSET_SIZE = ".pricelist.page.right.offset";

    //
    //  -------------------------------------------------------------------
    //

    //
    //  ПЭЙДЖИНГ ----------------------------------------------------------
    //

    /**
     * Количество страниц
     */
    private int pagesCount = -1;

    /**
     * Количество товаров
     */
    private int goodsCount = -1;

    /**
     * Размер страницы
     */
    private int pageSize = -1;

    /**
     *  Отступ от текущей страницы влево для паджинатора (кол-во страниц, слева от текущей)
     */
    private int _leftPageOffset = -1;

    /**
     * Отступ от текущей страницы вправо для паджинатора (кол-во страниц, справа от текущей)
     */
    private int _rightPageOffset = -1;

    /**
     * Получить (согласно настройкам) размер страницы (для пэйджинатора)
     */
    public int getPageSize()
    {
        gf().createIfNotExists(PRICELIST_PAGE_SIZE_KEY, 10);
        if (pageSize == -1) pageSize = gf().getInt(PRICELIST_PAGE_SIZE_KEY);
        return pageSize;
    }

    /**
     * Получить (согласно настройкам) размер отступа влево (в страницах) для пэйджинатора
     */
    public int getLeftPaggeOffset()
    {
        gf().createIfNotExists(PRICELIST_LEFT_PAGE_OFFSET_SIZE, 5);
        if (_leftPageOffset == -1) _leftPageOffset = gf().getInt(PRICELIST_LEFT_PAGE_OFFSET_SIZE);
        return _leftPageOffset;
    }

    /**
     * Получить (согласно настройкам) размер отступа вправо (в страницах) для пэйджинатора
     */
    public int getRightPaggeOffset()
    {
        gf().createIfNotExists(PRICELIST_RIGHT_PAGE_OFFSET_SIZE, 5);
        if (_rightPageOffset == -1) _rightPageOffset = gf().getInt(PRICELIST_RIGHT_PAGE_OFFSET_SIZE);
        return _rightPageOffset ;
    }

    public int getGoodsCount()
    {
        if (goodsCount == -1)
        {
            goodsCount = (int) gf().getGoodsCount(getSessionBean().get_pricelistFilter());
        }
        return goodsCount;
    }

    public int getPagesCount()
    {
        if (pagesCount == -1)
        {
            pagesCount = getGoodsCount() / getPageSize() + 1;
        }
        return pagesCount;
    }

    /**
     * Перейти к началу (на первую страницу)
     */
    public void toBegin()
    {
        applyPage();
        setPage(1);
    }

    /**
     * Перейти к концу (на последнюю страницу)
     */
    public void toEnd()
    {
        applyPage();
        setPage(getPagesCount());
    }

    /**
     * Отступить на несколько страниц назад
     */
    public void longPrevPage()
    {
        applyPage();
        int p = getPage() - getLeftPaggeOffset() - 1;
        if (p < 1) p = 1;
        setPage(p);
    }

    /**
     * Отступить на несколько страниц вперед
     */
    public void longNextPage()
    {
        applyPage();
        int p = getPage() + getRightPaggeOffset() + 1;
        if (p > getPagesCount()) p = getPagesCount();
        setPage(p);
    }

    /**
     * Перейти на страницу вперед
     */
    public void nextPage()
    {
        applyPage();
        if (getPage() < getPagesCount()) setPage(getPage() + 1);
    }

    /**
     * Перейти на страницу назад
     */
    public void prevPage()
    {
        applyPage();
        if (getPage() > 1) setPage(getPage() - 1);
    }

    /**
     * Получить номер текущей страницы
     */
    public int getPage()
    {
        return getSessionBean().getPricelistPage();
    }

    /**
     * Установить номер текущей страницы
     */
    public void setPage(int page)
    {
        getSessionBean().setPricelistPage(page);
    }

    /**
     * Применить текущую страницу
     */
    public void applyPage()
    {
        releasePricelistItems();
        goodsCount = -1;
        pagesCount = -1;
    }

    private void releasePricelistItems()
    {
        logger.debug("releasePricelistItems");
        getSessionBean().setPricelistItems(null);
    }

    /**
     * Получить номера страниц для отрисовки в пэйджинаторе
     */
    public List<PageIndex> getPageIndexes()
    {
        int minPage = getPage() - getLeftPaggeOffset();
        if (minPage < 1) minPage = 1;

        int maxPage = minPage + getLeftPaggeOffset() + getRightPaggeOffset();
        if (maxPage > getPagesCount()) maxPage = getPagesCount();

        List<PageIndex> result = new ArrayList<PageIndex>();
        for (int i = minPage; i <= maxPage; i++)
            result.add(new PageIndex(i, i == getPage()));

        return result;
    }

    /**
     * Применить фильтр
     */
    public void applyFilter()
    {
        logger.debug("Filter " + getSessionBean().get_pricelistFilter());
        releasePricelistItems();
        setPage(1);
        goodsCount = -1;
        pagesCount = -1;
    }

    /**
     * Получить номер первой страницы, которую необходимо отрисовать в пэйджинаторе
     */
    private int getPageStart()
    {
        int pageStart = getPage() * getPageSize() - getPageSize();
        if (pageStart < 0) pageStart = 0;
        return pageStart;
    }

    //
    //  -------------------------------------------------------------------
    //


    private List<ClientGroup> clientGroups;

    /**
     * Получить видимые элементы прайслиста, с учетом фильтра и страницы
     */
    public List<PricelistItem> getPageItems()
    {
        if (getSessionBean().getPricelistItems() == null)
        {            
            getSessionBean().setPricelistItems(gf().getPricelist(getPageStart(), getPageSize(), getSessionBean().get_pricelistFilter()));
        }
        return getSessionBean().getPricelistItems();
    }

    public void setItems(List<PricelistItem> items)
    {
        getSessionBean().setPricelistItems(items);
    }

    /**
     * Клиентские группы
     */
    public List<ClientGroup> getClientGroups()
    {
        if (clientGroups == null)
        {
            clientGroups = gf().getClientGroups();
            for (ClientGroup clientGroup : clientGroups) {
                Brand brand = gf().getBrandById(clientGroup.getBrandId());
                if (brand != null) {
                    clientGroup.setBrand(brand);
                }
            }

/*            Collections.sort(clientGroups, new Comparator<ClientGroup>() {
                public int compare(ClientGroup c1, ClientGroup c2) {
                    try
                    {
                        if (c1 == null || c2 == null) return 0;
                        if (c1.getBrand() == null || c2.getBrand() == null)
                        {
                            return c1.getName().compareTo(c2.getName());
                        }
                        if (c1.getBrandId() == c2.getBrandId())
                        {
                            return c1.getName().compareTo(c2.getName());
                        }
                        if (c1.getBrandId() != c2.getBrandId())
                        {
                            return c1.getBrand().getName().compareTo(c2.getBrand().getName());
                        }
                    }
                    catch (Exception e)
                    {                        
                    }
                    return 0;
                }

            });*/
        }
        return clientGroups;
    }

    public void commit()
    {
        logger.debug("Commit");
        try
        {
            for (PricelistItem item : getPageItems()) {
                logger.debug(item.getGood().getCode() + ": " + item.get(18).getValue() + " (" + item.get(18).hasChanged() + ")");
                gf().updatePricelistItem(item);

            }
                            
            setItems(null);
            facesInfo("Прейскурант обновлен");
        }
        catch (ValidationException ex)
        {
            logger.error(ex);
            ex.printStackTrace();
            ValidationResult validationResult = ex.getResult();
            for (ValidationError error : validationResult.getErrors())
                facesError(error.toHumanString());
        }
    }

    //
    //  ЗАКАЧКА ПРАЙСА С ПОМОЩЬЮ EXCEL --------------------------------------------------
    //

    private static final String TEMPLATE_PATH_DEFAULT = "C:\\PricelistTemplate.xls";
    private static final String TEMPLATE_PATH = ".pricelist.export.template";

    private String downloadExcelFileLink;

    public void generateExcelPricelist(String templatePath, String link) throws IOException
    {
        Workbook wb = new HSSFWorkbook(new FileInputStream(templatePath));
        wb.createSheet();
        Sheet sheet1 = wb.getSheetAt(0);

        //  Сначала обходим группы товаров
        List<Good> result = new ArrayList<Good>();
        for (GoodType goodType : gf().getGoodTypes())
        {
            GoodsFilter goodsFilter = new GoodsFilter();
            goodsFilter.setGoodTypeId(goodType.getId());
            List<Good> goods = gf().getGoods(0, Integer.MAX_VALUE, goodsFilter);

            //  Теперь обходим товары из этой группы товаров
            for (Good good : goods)
            {
                good.setGoodType(goodType);

                //  Получение цен для товра
                gf().addPricesToGood(good);
                result.add(good);
            }
        }

        List<ClientGroup> clientGroups = getClientGroups();
        Row row = sheet1.getRow(0);
        Cell cell;
        for (int i = 0; i < clientGroups.size(); i++)
        {
            ClientGroup clientGroup = clientGroups.get(i);
            cell = row.createCell(8+i);
            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(clientGroup.getName());
        }

        for (Good good : result)
        {
            row = sheet1.createRow(1 + result.indexOf(good));

            //  Код
            cell = row.createCell(0);
            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(good.getCode());

            //  Группа товаров
            cell = row.createCell(1);
            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(good.getGoodType().getName());

            //  Наименование товара
            cell = row.createCell(2);
            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(good.getName());

            //  M&H
            cell = row.createCell(3);
            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(good.getMh());

            //  o.e.
            cell = row.createCell(4);
            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(good.getOe());

            //  Применимость
            cell = row.createCell(5);
            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(good.getPr());

            //  Групповая тара
            cell = row.createCell(6);
            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(good.getPackageCount());

            //  ТД
            cell = row.createCell(7);
            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(good.getMinPrice());

            for (int i = 0; i < clientGroups.size(); i++)
            {
                ClientGroup clientGroup = clientGroups.get(i);
                float price = gf().getPricesMap(good.getId()).get(clientGroup.getId());

                cell = row.createCell(8+i);
                cell.setCellType(Cell.CELL_TYPE_STRING);
                cell.setCellValue(String.valueOf(price));
            }


        }

        FileOutputStream fos = new FileOutputStream(link);
        wb.write(fos);
        fos.flush();
        fos.close();
    }

    public void prepareExcelFile() throws IOException
    {
        try
        {
            logger.debug("prepareExcelFile()");

            gf().createIfNotExists(RestsExportBean.TEMP_CATALOG, RestsExportBean.DEFAULT_TEMP_CATALOG);
            String tempCatalog = gf().get(RestsExportBean.TEMP_CATALOG);
            logger.debug("Temp catalog is: " + tempCatalog);

            gf().createIfNotExists(TEMPLATE_PATH, TEMPLATE_PATH_DEFAULT);
            String templatePath = gf().get(TEMPLATE_PATH);
            logger.debug("Template catalog is: " + templatePath);

            String uid = UUID.randomUUID().toString();
            logger.debug("Report uid is: " + uid);

            String tempFile = tempCatalog + File.separator + uid + ".xls";
            logger.debug("Temp file is: " + tempFile);

            generateExcelPricelist(templatePath, tempFile);

            logger.debug("Generated successfuly!");
            HttpServletRequest request = (HttpServletRequest) getFacesContext().getExternalContext().getRequest();

            logger.debug("Publishing...");
            downloadExcelFileLink = FilePublisher.retrieveFile(request, tempFile, uid + ".xls");
            logger.debug("Published to: " + downloadExcelFileLink);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            logger.error(e);
            facesError("Невозможно осуществить выгрузку данных");
        }
    }

    public String getDownloadExcelFileLink()
    {
        return downloadExcelFileLink;
    }

    public void setDownloadExcelFileLink(String downloadExcelFileLink)
    {
        this.downloadExcelFileLink = downloadExcelFileLink;
    }

    //
    //  ---------------------------------------------------------------------------------
    //
}